<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/favicon.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon.png">
  <link rel="mask-icon" href="/images/favicon.png" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.css">


<script id="hexo-configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    hostname: new URL('https://codz-me.vercel.app').hostname,
    root: '/',
    scheme: 'Muse',
    version: '7.7.1',
    exturl: false,
    sidebar: {"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},
    copycode: {"enable":false,"show_result":false,"style":null},
    back2top: {"enable":true,"sidebar":false,"scrollpercent":false},
    bookmark: {"enable":false,"color":"#222","save":"auto"},
    fancybox: true,
    mediumzoom: false,
    lazyload: false,
    pangu: false,
    comments: {"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},
    algolia: {
      appID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    },
    localsearch: {"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},
    path: '',
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}
  };
</script>

  <meta name="description" content="背景ngrok官网被q，而且访问速度慢，最主要的是不支持域名绑定，每次启动都是随机的二级域名，333 ngrok.cc-Sunny-Ngrok内网转发，服务器在香港，访问速度也慢，支持自定义系统域名，但只能定义一个（可以先定义TCP端口转发，保存后编辑，可以修改成系统分配域名，这样子就可以有多个自定义的系统域名，然并卵，客户端连接不上，一直提示该域名已被注册，官方做限制了吧）。 对比了上面两个服务">
<meta property="og:type" content="article">
<meta property="og:title" content="从编译到使用 - ngrok 服务搭建">
<meta property="og:url" content="https://codz-me.vercel.app/2016/07/21/ngrok-compile-and-run-online/index.html">
<meta property="og:site_name" content="Code Is Poetry">
<meta property="og:description" content="背景ngrok官网被q，而且访问速度慢，最主要的是不支持域名绑定，每次启动都是随机的二级域名，333 ngrok.cc-Sunny-Ngrok内网转发，服务器在香港，访问速度也慢，支持自定义系统域名，但只能定义一个（可以先定义TCP端口转发，保存后编辑，可以修改成系统分配域名，这样子就可以有多个自定义的系统域名，然并卵，客户端连接不上，一直提示该域名已被注册，官方做限制了吧）。 对比了上面两个服务">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2016-07-21T12:39:00.000Z">
<meta property="article:modified_time" content="2017-02-20T00:42:32.000Z">
<meta property="article:author" content="laudukang">
<meta property="article:tag" content="ngrok">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://codz-me.vercel.app/2016/07/21/ngrok-compile-and-run-online/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome: false,
    isPost: true
  };
</script>

  <title>从编译到使用 - ngrok 服务搭建 | Code Is Poetry</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">Code Is Poetry</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
  </div>

  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-fw fa-user"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>归档</a>

  </li>
        <li class="menu-item menu-item-commonweal">

    <a href="/404/" rel="section"><i class="fa fa-fw fa-heartbeat"></i>公益 404</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block " lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2016/07/21/ngrok-compile-and-run-online/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          从编译到使用 - ngrok 服务搭建
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2017-02-20 08:42:32 08:42:32" itemprop="dateModified" datetime="2017-02-20T08:42:32+08:00">2017-02-20 08:42:32</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index">
                    <span itemprop="name">Linux</span>
                  </a>
                </span>
            </span>

          
            <span id="/2016/07/21/ngrok-compile-and-run-online/" class="post-meta-item leancloud_visitors" data-flag-title="从编译到使用 - ngrok 服务搭建" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p><a href="https://ngrok.com/" target="_blank" rel="noopener">ngrok官网</a>被q，而且访问速度慢，最主要的是不支持域名绑定，每次启动都是随机的二级域名，333</p>
<p><a href="https://www.ngrok.cc/" target="_blank" rel="noopener">ngrok.cc-Sunny-Ngrok内网转发</a>，服务器在香港，访问速度也慢，支持自定义系统域名，但只能定义一个（可以先定义TCP端口转发，保存后编辑，可以修改成系统分配域名，这样子就可以有多个自定义的系统域名，然并卵，客户端连接不上，一直提示该域名已被注册，官方做限制了吧）。</p>
<p>对比了上面两个服务，加上自己的需求：</p>
<ul>
<li>需要多个自定义的域名；</li>
<li>尽量提升访问速度；决定自己搭建一个ngrok服务。</li>
</ul>
<p>搭建ngrok服务需要的资源：</p>
<ul>
<li>一个域名，需要定义泛解析；</li>
<li>一台ECS，需要公网IP</li>
</ul>
<p>以下操作建议在Ubuntu上尝试，不建议在Windows上尝试（花了一个晚上搞都没搞成功，第二天早上花一个小时在Ubuntu上完美运行）</p>
<h2 id="拉取ngrok源码"><a href="#拉取ngrok源码" class="headerlink" title="拉取ngrok源码"></a>拉取ngrok源码</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> git@github.com:inconshreveable/ngrok.git /work/ngrok</span><br></pre></td></tr></table></figure>

<p>使用ngrok.com官方服务时，我们使用的是官方的SSL证书。</p>
<p>自建ngrokd服务，如果不想买SSL证书，我们需要生成自己的自签名证书，并编译一个携带该证书的ngrok客户端。</p>
<p>证书生成过程需要一个<code>NGROK_BASE_DOMAIN</code>。</p>
<p>以ngrok官方随机生成的地址693c358d.ngrok.com为例，其<code>NGROK_BASE_DOMAIN</code>就是<code>ngrok.com</code>，如果你要提供服务的地址为<code>example.ngrok.xxx.com</code>，那<code>NGROK_BASE_DOMAIN</code>就应该是<code>ngrok.xxx.com</code>。</p>
<p>这里以<code>NGROK_BASE_DOMAIN=&quot;codz.me&quot;</code>为例，生成证书的命令如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /work/ngrok</span><br><span class="line">openssl genrsa -out rootCA.key 2048</span><br><span class="line">openssl req -x509 -new -nodes -key rootCA.key -subj <span class="string">"/CN=codz.me"</span> -days 5000 -out rootCA.pem</span><br><span class="line">openssl genrsa -out device.key 2048</span><br><span class="line">openssl req -new -key device.key -subj <span class="string">"/CN=codz.me"</span> -out device.csr</span><br><span class="line">openssl x509 -req -<span class="keyword">in</span> device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000</span><br></pre></td></tr></table></figure>

<p>ngrok目录下新建了如下文件</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">-rw-r--r-- <span class="number">1</span> root root  <span class="number">985</span> Jul <span class="number">21</span> <span class="number">08</span>:<span class="number">52</span> device.crt</span><br><span class="line">-rw-r--r-- <span class="number">1</span> root root  <span class="number">895</span> Jul <span class="number">21</span> <span class="number">08</span>:<span class="number">52</span> device.csr</span><br><span class="line">-rw-r--r-- <span class="number">1</span> root root <span class="number">1679</span> Jul <span class="number">21</span> <span class="number">08</span>:<span class="number">52</span> device.key</span><br><span class="line">-rw-r--r-- <span class="number">1</span> root root <span class="number">1675</span> Jul <span class="number">21</span> <span class="number">08</span>:<span class="number">51</span> rootCA.key</span><br><span class="line">-rw-r--r-- <span class="number">1</span> root root <span class="number">1103</span> Jul <span class="number">21</span> <span class="number">08</span>:<span class="number">52</span> rootCA.pem</span><br><span class="line">-rw-r--r-- <span class="number">1</span> root root   <span class="number">17</span> Jul <span class="number">21</span> <span class="number">08</span>:<span class="number">52</span> rootCA.srl</span><br></pre></td></tr></table></figure>

<p>ngrok通过bindata将ngrok源码目录下的assets目录打包到可执行文件(ngrokd和ngrok)中去，<code>assets/client/tls和assets/server/tls</code>下分别存放着用于ngrok和ngrokd的默认证书文件。</p>
<p>我们需要将它们替换成我们自己生成的，因此这一步务必放在编译可执行文件之前。</p>
<p>所以，执行下面拷贝命令：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cp rootCA.pem assets/client/tls/ngrokroot.crt</span><br><span class="line">cp device.crt assets/server/tls/snakeoil.crt</span><br><span class="line">cp device.key assets/server/tls/snakeoil.key</span><br></pre></td></tr></table></figure>

<h2 id="搭建go环境"><a href="#搭建go环境" class="headerlink" title="搭建go环境"></a>搭建go环境</h2><p><a href="https://golang.org/" target="_blank" rel="noopener">Golang官网</a>被q，下载安装包特么慢，<a href="https://golangtc.com/download" target="_blank" rel="noopener">Golang中国</a>提供下载站点，我使用的是1.6.3版本；</p>
<p>下载并解压到go的默认安装路径<code>/usr/local/go</code></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /work/download</span><br><span class="line">wget http://www.golangtc.com/static/go/1.6.3/go1.6.3.linux-amd64.tar.gz</span><br><span class="line">tar -zxvf go1.6.3.linux-amd64.tar.gz -C /usr/<span class="built_in">local</span></span><br></pre></td></tr></table></figure>

<p>修改PATH</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/profile</span><br><span class="line"><span class="built_in">export</span> GOROOT=/usr/<span class="built_in">local</span>/go</span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$PATH</span>:<span class="variable">$GOROOT</span>/bin</span><br><span class="line"><span class="built_in">source</span> /etc/profile</span><br></pre></td></tr></table></figure>
<p>正确配置后，go env可以查看得到当前go的环境</p>
<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">GOARCH</span>=<span class="string">"amd64"</span></span><br><span class="line"><span class="attr">GOBIN</span>=<span class="string">""</span></span><br><span class="line"><span class="attr">GOEXE</span>=<span class="string">""</span></span><br><span class="line"><span class="attr">GOHOSTARCH</span>=<span class="string">"amd64"</span></span><br><span class="line"><span class="attr">GOHOSTOS</span>=<span class="string">"linux"</span></span><br><span class="line"><span class="attr">GOOS</span>=<span class="string">"linux"</span></span><br><span class="line"><span class="attr">GOPATH</span>=<span class="string">""</span></span><br><span class="line"><span class="attr">GORACE</span>=<span class="string">""</span></span><br><span class="line"><span class="attr">GOROOT</span>=<span class="string">"/usr/local/go"</span></span><br><span class="line"><span class="attr">GOTOOLDIR</span>=<span class="string">"/usr/local/go/pkg/tool/linux_amd64"</span></span><br><span class="line"><span class="attr">GO15VENDOREXPERIMENT</span>=<span class="string">"1"</span></span><br><span class="line"><span class="attr">CC</span>=<span class="string">"gcc"</span></span><br><span class="line"><span class="attr">GOGCCFLAGS</span>=<span class="string">"-fPIC -m64 -pthread -fmessage-length=0"</span></span><br><span class="line"><span class="attr">CXX</span>=<span class="string">"g++"</span></span><br><span class="line"><span class="attr">CGO_ENABLED</span>=<span class="string">"1"</span></span><br></pre></td></tr></table></figure>

<h2 id="编译安装"><a href="#编译安装" class="headerlink" title="编译安装"></a>编译安装</h2><p>进入<code>/work/ngrok</code>目录</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make release-server release-client</span><br></pre></td></tr></table></figure>

<p>正常的话，<code>ngrok/bin</code>目录下应该有<code>ngrokd</code>和<code>ngrok</code>两个可执行文件，前面一个是服务端的，后面一个是客户端的；</p>
<p>需要Windows下的<code>ngrok.exe</code>可以通过下面命令构建，正常的话<code>ngrok/bin/windows_amd64</code>下会生成的<code>ngrok.exe</code>文件；</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">GOOS</span>=windows <span class="attribute">GOARCH</span>=amd64 make release-client</span><br></pre></td></tr></table></figure>

<p>编译mac客户端（没实际操作）</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">GOOS</span>=darwin <span class="attribute">GOARCH</span>=amd64 make release-client</span><br></pre></td></tr></table></figure>

<p>make很可能出现的错误有（来自Windows下的错误信息，Ubuntu下跑一切正常）</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">package archive/zip: unrecognized import path "archive/zip" (import path does not <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br><span class="line"><span class="keyword">package</span> <span class="keyword">bytes</span>: unrecognized <span class="keyword">import</span> <span class="keyword">path</span> <span class="string">"bytes"</span> (<span class="keyword">import</span> <span class="keyword">path</span> does <span class="keyword">not</span> <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br><span class="line"><span class="keyword">package</span> <span class="keyword">encoding</span>/<span class="keyword">json</span>: unrecognized <span class="keyword">import</span> <span class="keyword">path</span> <span class="string">"encoding/json"</span> (<span class="keyword">import</span> <span class="keyword">path</span> does <span class="keyword">not</span> <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br><span class="line"><span class="keyword">package</span> <span class="keyword">encoding</span>/<span class="keyword">xml</span>: unrecognized <span class="keyword">import</span> <span class="keyword">path</span> <span class="string">"encoding/xml"</span> (<span class="keyword">import</span> <span class="keyword">path</span> does <span class="keyword">not</span> <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br><span class="line"><span class="keyword">package</span> <span class="keyword">errors</span>: unrecognized <span class="keyword">import</span> <span class="keyword">path</span> <span class="string">"errors"</span> (<span class="keyword">import</span> <span class="keyword">path</span> does <span class="keyword">not</span> <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br><span class="line"><span class="keyword">package</span> expvar: unrecognized <span class="keyword">import</span> <span class="keyword">path</span> <span class="string">"expvar"</span> (<span class="keyword">import</span> <span class="keyword">path</span> does <span class="keyword">not</span> <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br><span class="line"><span class="keyword">package</span> flag: unrecognized <span class="keyword">import</span> <span class="keyword">path</span> <span class="string">"flag"</span> (<span class="keyword">import</span> <span class="keyword">path</span> does <span class="keyword">not</span> <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br><span class="line"><span class="keyword">package</span> fmt: unrecognized <span class="keyword">import</span> <span class="keyword">path</span> <span class="string">"fmt"</span> (<span class="keyword">import</span> <span class="keyword">path</span> does <span class="keyword">not</span> <span class="keyword">begin</span> <span class="keyword">with</span> hostname)</span><br></pre></td></tr></table></figure>

<h2 id="启动ngrok"><a href="#启动ngrok" class="headerlink" title="启动ngrok"></a>启动ngrok</h2><h3 id="服务端启动"><a href="#服务端启动" class="headerlink" title="服务端启动"></a>服务端启动</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /work/ngrok/bin</span><br><span class="line">ngrokd -domain=<span class="string">"codz.me"</span> -httpAddr=<span class="string">":8088"</span> -httpsAddr=<span class="string">":8089"</span></span><br></pre></td></tr></table></figure>
<p>-domain的内容需要与上面生成证书所填的<code>NGROK_BASE_DOMAIN</code>一致；</p>
<p>自定义http、https提供服务的端口，据此你使用的二级域名应该是 http://[自定义].codz.me:8088</p>
<p>其他有用的启动脚本</p>
<ul>
<li><p>后台启动，输出日志</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup ngrokd -domain=<span class="string">"codz.me"</span> -httpAddr=<span class="string">":8088"</span> -httpsAddr=<span class="string">":8089"</span> &gt;/tmp/ngrok.log 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure>
</li>
<li><p>后台启动不输出日志</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup ngrokd -domain=<span class="string">"codz.me"</span> -httpAddr=<span class="string">":8088"</span> -httpsAddr=<span class="string">":8089"</span> &gt;/dev/null 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h3 id="客户端启动"><a href="#客户端启动" class="headerlink" title="客户端启动"></a>客户端启动</h3><p>拷贝编译好的ngrok客户端可执行文件到需要的机子上，给予执行权限，创建配置文件<code>ngrok.cfg</code>：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server_addr:</span> <span class="string">"codz.me:4443"</span></span><br><span class="line"><span class="attr">trust_host_root_certs:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="attr">tunnels:</span></span><br><span class="line">  <span class="attr">www:</span></span><br><span class="line">   <span class="attr">subdomain:</span> <span class="string">"test"</span></span><br><span class="line">   <span class="attr">proto:</span></span><br><span class="line">    <span class="attr">http:</span> <span class="number">192.168</span><span class="number">.1</span><span class="number">.121</span><span class="string">:8000</span></span><br></pre></td></tr></table></figure>

<p>其中，<code>server_addr</code>需要跟<code>NGROK_BASE_DOMAIN</code>填写一致，否则服务端会报证书错误；</p>
<p><code>trust_host_root_certs</code>需要设置为false；</p>
<p><code>trust_host_root_certs</code>参数指示建立TLS连接到服务器时ngrok信任的根证书在计算机上。默认情况下，ngrok只信任的ngrok.com根证书；</p>
<p><code>trust_host_root_certs</code>，对于ngrok官方server一般为<code>true</code>，现在官网国内不能用，通常为自编译的，有自己的证书，所以要设为<code>false</code>。</p>
<p>启动客户端ngrok，之后就可以使用<code>http://test.codz.me:8088</code>来访问本地<code>192.168.121:8000</code>的资源了</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./ngrok -config ngrok.cfg start www</span><br></pre></td></tr></table></figure>

<p>配置文件写法，来自ngrok.cc</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server_addr:</span> <span class="string">"server.ngrok.cc:4443"</span></span><br><span class="line"><span class="attr">auth_token:</span> <span class="string">""</span> <span class="comment">#授权token，在www.ngrok.cc平台注册账号获取</span></span><br><span class="line"><span class="attr">tunnels:</span></span><br><span class="line">  <span class="attr">sunny:</span></span><br><span class="line">   <span class="attr">subdomain:</span> <span class="string">"sunny"</span> <span class="comment">#定义服务器分配域名前缀，跟平台上的要一样</span></span><br><span class="line">   <span class="attr">proto:</span></span><br><span class="line">    <span class="attr">http:</span> <span class="number">80</span> <span class="comment">#映射端口，不加ip默认本机</span></span><br><span class="line">    <span class="attr">https:</span> <span class="number">80</span></span><br><span class="line">  <span class="attr">web:</span></span><br><span class="line">   <span class="attr">subdomain:</span> <span class="string">"web"</span> <span class="comment">#定义服务器分配域名前缀</span></span><br><span class="line">   <span class="attr">proto:</span></span><br><span class="line">    <span class="attr">http:</span> <span class="number">192.168</span><span class="number">.1</span><span class="number">.100</span><span class="string">:80</span> <span class="comment">#映射端口，可以通过加ip为内网任意一台映射</span></span><br><span class="line">    <span class="attr">https:</span> <span class="number">192.168</span><span class="number">.1</span><span class="number">.100</span><span class="string">:80</span></span><br><span class="line">  <span class="attr">web1:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">"www.sunnyos.com"</span></span><br><span class="line">    <span class="attr">proto:</span></span><br><span class="line">      <span class="attr">http:</span> <span class="number">80</span></span><br><span class="line">  <span class="attr">web2:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">"sunnyos.com"</span></span><br><span class="line">    <span class="attr">proto:</span></span><br><span class="line">      <span class="attr">http:</span> <span class="number">80</span>  </span><br><span class="line">  <span class="attr">ssh:</span></span><br><span class="line">   <span class="attr">remote_port:</span> <span class="number">50001</span> <span class="comment">#服务器分配tcp转发端口，如果不填写此项则又服务器分配</span></span><br><span class="line">   <span class="attr">proto:</span></span><br><span class="line">    <span class="attr">tcp:</span> <span class="number">22</span> <span class="comment">#映射本地的22端口</span></span><br><span class="line">  <span class="attr">ssh1:</span> <span class="comment">#将由服务器分配端口</span></span><br><span class="line">    <span class="attr">proto:</span></span><br><span class="line">      <span class="attr">tcp:</span> <span class="number">21</span></span><br></pre></td></tr></table></figure>


<p>至此，all done.</p>
<p>实测，单个用户通过ngrok访问内网速度有所提升；</p>
<p>多个用户同时访问效果不是很明显，可能与ECS带宽有关（→_→ 1Mbps），ngrok使用多个自定义域名目的已达成，这是重点。</p>
<p>参考：</p>
<ul>
<li><a href="https://aotu.io/notes/2016/02/19/ngrok/" target="_blank" rel="noopener">https://aotu.io/notes/2016/02/19/ngrok/</a></li>
<li><a href="http://tonybai.com/2015/03/14/selfhost-ngrok-service" target="_blank" rel="noopener">http://tonybai.com/2015/03/14/selfhost-ngrok-service</a></li>
<li><a href="http://blog.csdn.net/tao_627/article/details/17191977" target="_blank" rel="noopener">http://blog.csdn.net/tao_627/article/details/17191977</a></li>
<li><a href="http://briteming.blogspot.com/2016/04/ngrok.html" target="_blank" rel="noopener">http://briteming.blogspot.com/2016/04/ngrok.html</a></li>
</ul>

    </div>

    
    
    

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/ngrok/" rel="tag"># ngrok</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2016/05/30/elasticsearch-note-2/" rel="prev" title="（二）Elasticsearch学习笔记：CURD">
      <i class="fa fa-chevron-left"></i> （二）Elasticsearch学习笔记：CURD
    </a></div>
      <div class="post-nav-item">
    <a href="/2016/07/28/ubuntu-desktop-boot-to-char-interface/" rel="next" title="Ubuntu Desktop 16.04 设置默认启动到字符界面">
      Ubuntu Desktop 16.04 设置默认启动到字符界面 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  

  </div>


          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let activeClass = CONFIG.comments.activeClass;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#背景"><span class="nav-number">1.</span> <span class="nav-text">背景</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#拉取ngrok源码"><span class="nav-number">2.</span> <span class="nav-text">拉取ngrok源码</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#搭建go环境"><span class="nav-number">3.</span> <span class="nav-text">搭建go环境</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#编译安装"><span class="nav-number">4.</span> <span class="nav-text">编译安装</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#启动ngrok"><span class="nav-number">5.</span> <span class="nav-text">启动ngrok</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#服务端启动"><span class="nav-number">5.1.</span> <span class="nav-text">服务端启动</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#客户端启动"><span class="nav-number">5.2.</span> <span class="nav-text">客户端启动</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="laudukang"
      src="/images/head.png">
  <p class="site-author-name" itemprop="name">laudukang</p>
  <div class="site-description" itemprop="description">Bug Not Found</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">68</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">10</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">25</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/laudukang" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;laudukang" rel="noopener" target="_blank"><i class="fa fa-fw fa-github"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://gitee.com/laudukang" title="Gitee → https:&#x2F;&#x2F;gitee.com&#x2F;laudukang" rel="noopener" target="_blank"><i class="fa fa-fw fa-github-alt"></i>Gitee</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://stackoverflow.com/users/5621049/laudukang" title="StackOverflow → https:&#x2F;&#x2F;stackoverflow.com&#x2F;users&#x2F;5621049&#x2F;laudukang" rel="noopener" target="_blank"><i class="fa fa-fw fa-stack-overflow"></i>StackOverflow</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://www.google.com/maps/place/%E6%B7%B1%E5%9C%B3%E5%B8%82%E8%BD%AF%E4%BB%B6%E4%BA%A7%E4%B8%9A%E5%9F%BA%E5%9C%B0/@22.5244896,113.9382973,17z/data=!3m1!4b1!4m5!3m4!1s0x3403ee17d008a019:0xbb7b06b73d856c14!8m2!3d22.5244896!4d113.9382973" title="Map → https:&#x2F;&#x2F;www.google.com&#x2F;maps&#x2F;place&#x2F;%E6%B7%B1%E5%9C%B3%E5%B8%82%E8%BD%AF%E4%BB%B6%E4%BA%A7%E4%B8%9A%E5%9F%BA%E5%9C%B0&#x2F;@22.5244896,113.9382973,17z&#x2F;data&#x3D;!3m1!4b1!4m5!3m4!1s0x3403ee17d008a019:0xbb7b06b73d856c14!8m2!3d22.5244896!4d113.9382973" rel="noopener" target="_blank"><i class="fa fa-fw fa-map-marker"></i>Map</a>
      </span>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
  
  &copy; 2015 – 
  <span itemprop="copyrightYear">2025</span>
  <span class="with-love">
    <i class="fa fa-heart icon-next-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">laudukang</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> 强力驱动 v4.2.0
  </div>
  <span class="post-meta-divider">|</span>
  <div class="theme-info">主题 – <a href="https://muse.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Muse</a> v7.7.1
  </div>

        
<div class="busuanzi-count">
  <script pjax async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
</div>






  <script pjax>
  function leancloudSelector(url) {
    url = encodeURI(url);
    return document.getElementById(url).querySelector('.leancloud-visitors-count');
  }
  if (CONFIG.page.isPost) {
    function addCount(Counter) {
      var visitors = document.querySelector('.leancloud_visitors');
      var url = decodeURI(visitors.getAttribute('id'));
      var title = visitors.getAttribute('data-flag-title');

      Counter('get', `/classes/Counter?where=${JSON.stringify({ url })}`)
        .then(response => response.json())
        .then(({ results }) => {
          if (results.length > 0) {
            var counter = results[0];
              leancloudSelector(url).innerText = counter.time + 1;
            Counter('put', '/classes/Counter/' + counter.objectId, { time: { '__op': 'Increment', 'amount': 1 } })
              .then(response => response.json())
              .catch(error => {
                console.error('Failed to save visitor count', error);
              })
          } else {
              Counter('post', '/classes/Counter', { title: title, url: url, time: 1 })
                .then(response => response.json())
                .then(() => {
                  leancloudSelector(url).innerText = 1;
                })
                .catch(error => {
                  console.error('Failed to create', error);
                });
          }
        })
        .catch(error => {
          console.error('LeanCloud Counter Error', error);
        });
    }
  } else {
    function showTime(Counter) {
      var visitors = document.querySelectorAll('.leancloud_visitors');
      var entries = [...visitors].map(element => {
        return decodeURI(element.getAttribute('id'));
      });

      Counter('get', `/classes/Counter?where=${JSON.stringify({ url: { '$in': entries } })}`)
        .then(response => response.json())
        .then(({ results }) => {
          if (results.length === 0) {
            document.querySelectorAll('.leancloud_visitors .leancloud-visitors-count').forEach(element => {
              element.innerText = 0;
            });
            return;
          }
          for (let item of results) {
            let { url, time } = item;
            leancloudSelector(url).innerText = time;
          }
          for (let url of entries) {
            var element = leancloudSelector(url);
            if (element.innerText == '') {
              element.innerText = 0;
            }
          }
        })
        .catch(error => {
          console.error('LeanCloud Counter Error', error);
        });
    }
  }

  fetch('https://app-router.leancloud.cn/2/route?appId=CPfRDhOlTyfkHW155W3Kx3H1-gzGzoHsz')
    .then(response => response.json())
    .then(({ api_server }) => {
      var Counter = (method, url, data) => {
        return fetch(`https://${api_server}/1.1${url}`, {
          method: method,
          headers: {
            'X-LC-Id': 'CPfRDhOlTyfkHW155W3Kx3H1-gzGzoHsz',
            'X-LC-Key': 'TX05RQSQMd8fbL7RaJNADS7S',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
      };
      if (CONFIG.page.isPost) {
        if (CONFIG.hostname !== location.hostname) return;
        addCount(Counter);
      } else if (document.querySelectorAll('.post-title-link').length >= 1) {
        showTime(Counter);
      }
    });
  </script>


      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/pjax/pjax.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>

  <script>
var pjax = new Pjax({
  selectors: [
    'head title',
    '#page-configurations',
    '.content-wrap',
    '.post-toc-wrap',
    '#pjax'
  ],
  switches: {
    '.post-toc-wrap': Pjax.switches.innerHTML
  },
  analytics: false,
  cacheBust: false,
  scrollTo : !CONFIG.bookmark.enable
});

window.addEventListener('pjax:success', () => {
  document.querySelectorAll('script[pjax], script#page-configurations, #pjax script').forEach(element => {
    var code = element.text || element.textContent || element.innerHTML || '';
    var parent = element.parentNode;
    parent.removeChild(element);
    var script = document.createElement('script');
    if (element.id) {
      script.id = element.id;
    }
    if (element.className) {
      script.className = element.className;
    }
    if (element.type) {
      script.type = element.type;
    }
    if (element.src) {
      script.src = element.src;
      // Force synchronous loading of peripheral JS.
      script.async = false;
    }
    if (element.getAttribute('pjax') !== null) {
      script.setAttribute('pjax', '');
    }
    if (code !== '') {
      script.appendChild(document.createTextNode(code));
    }
    parent.appendChild(script);
  });
  NexT.boot.refresh();
  // Define Motion Sequence & Bootstrap Motion.
  if (CONFIG.motion.enable) {
    NexT.motion.integrator
      .init()
      .add(NexT.motion.middleWares.subMenu)
      .add(NexT.motion.middleWares.postList)
      .bootstrap();
  }
  NexT.utils.updateSidebarPosition();
});
</script>




  















    <div id="pjax">
  

  
<script>window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };</script><script defer src="/_vercel/insights/script.js" data-endpoint="/this-is-vercel-insights"></script><script>window.si = window.si || function () { (window.siq = window.siq || []).push(arguments); };</script><script defer src="/_vercel/speed-insights/script.js" data-endpoint="/this-is-vercel-insights-speed"></script>
    </div>
</body>
</html>
